﻿using System;
using System.Collections.Generic;
using Jayden.Dll.Core.Persistence.Models;

namespace Jayden.Dll.Core.Persistence
{
	public class DataAccessManager : IDisposable
	{
		private Configuration m_Configuration;
		private UnitOfWork m_UnitOfWork;
		private Dictionary<Entity, DataAccess> m_DataAccesses = null;

		public DataAccessManager(Configuration config, UnitOfWork uow)
		{
			if (config == null)
				throw new ArgumentNullException("config");
			m_Configuration = config;
			m_UnitOfWork = uow;
		}

		private void LoadConfiguration()
		{
			if (m_DataAccesses == null && m_UnitOfWork != null && m_Configuration != null)
			{
				m_DataAccesses = new Dictionary<Entity, DataAccess>();
				string[] entities = m_Configuration.GetValues("DataAccess/@entity");
				foreach (string entityName in entities)
				{
					string xpath = string.Format("DataAccess[@entity=\"{0}\"]", entityName);
					Configuration subConfig = m_Configuration.GetConfiguration(xpath);
					Entity entity = m_UnitOfWork.Model.GetEntity(entityName);
					Type dataAccessType = Type.GetType(subConfig.GetValue("@type"), true);
					DataAccess dataAccess = Activator.CreateInstance(dataAccessType, subConfig, m_UnitOfWork, entity) as DataAccess;
					m_DataAccesses.Add(entity, dataAccess);
				}
			}
		}

		public void BeginTransaction()
		{
			LoadConfiguration();
			foreach (DataAccess dataAccess in m_DataAccesses.Values)
				dataAccess.BeginTransaction();
		}
		public void CommitTransaction()
		{
			foreach (DataAccess dataAccess in m_DataAccesses.Values)
				dataAccess.CommitTransaction();
		}
		public void RollbackTransaction()
		{
			foreach (DataAccess dataAccess in m_DataAccesses.Values)
				dataAccess.RollbackTransaction();
		}

		public DataAccess GetDataAccess(Entity entity)
		{
			LoadConfiguration();
			return m_DataAccesses[entity];
		}

		public D GetDataAccess<D,T>() where D : DataAccess<T> where T: Object
		{
			return (D)GetDataAccess<T>();
		}

		public DataAccess<T> GetDataAccess<T>() where T : Object
		{
			LoadConfiguration();
			Type t = typeof(T);
			foreach (KeyValuePair<Entity, DataAccess> dataAccess in m_DataAccesses)
				if (dataAccess.Key.Type.Equals(t))
					return (DataAccess<T>)dataAccess.Value;
			return null;
		}

		public void Dispose()
		{
			m_UnitOfWork = null;
			if (m_DataAccesses != null)
			{
				foreach (KeyValuePair<Entity, DataAccess> pair in m_DataAccesses)
					if (pair.Value != null)
						pair.Value.Dispose();
				m_DataAccesses = null;
			}
		}
	}
}
